/* main.c -- Battlefield: Bad Company 2 .so loader
 *
 * Copyright (C) 2021 Andy Nguyen
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE file for details.
 */

#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <psp2/io/dirent.h>
#include <psp2/io/fcntl.h>
#include <psp2/kernel/clib.h>
#include <psp2/kernel/threadmgr.h>
#include <psp2/audioout.h>
#include <psp2/ctrl.h>
#include <psp2/power.h>
#include <psp2/touch.h>
#include <kubridge.h>
#include <vitashark.h>
#include <vitaGL.h>

#include "main.h"
#include "config.h"
#include "dialog.h"
#include "so_util.h"
#include "jni.h"
#include "utils.h"
#include "patch.h"
#include "dynlib.h"
#include "pthread_patch.h"

int _newlib_heap_size_user = MEMORY_NEWLIB_MB * 1024 * 1024;

so_module so_mod;
/*
enum
{
	ACTION_DOWN = 1,
	ACTION_UP = 2,
	ACTION_MOVE = 3,
};

enum
{
	AKEYCODE_DPAD_UP = 19,
	AKEYCODE_DPAD_DOWN = 20,
	AKEYCODE_DPAD_LEFT = 21,
	AKEYCODE_DPAD_RIGHT = 22,
	AKEYCODE_A = 29,
	AKEYCODE_B = 30,
	AKEYCODE_BUTTON_X = 99,
	AKEYCODE_BUTTON_Y = 100,
	AKEYCODE_BUTTON_L1 = 102,
	AKEYCODE_BUTTON_R1 = 103,
	AKEYCODE_BUTTON_START = 108,
	AKEYCODE_BUTTON_SELECT = 109,
};

typedef struct
{
	uint32_t sce_button;
	uint32_t android_button;
} ButtonMapping;

static ButtonMapping mapping[] = {
	{SCE_CTRL_UP, AKEYCODE_DPAD_UP},
	{SCE_CTRL_DOWN, AKEYCODE_DPAD_DOWN},
	{SCE_CTRL_LEFT, AKEYCODE_DPAD_LEFT},
	{SCE_CTRL_RIGHT, AKEYCODE_DPAD_RIGHT},
	{SCE_CTRL_CROSS, AKEYCODE_A},
	{SCE_CTRL_CIRCLE, AKEYCODE_B},
	{SCE_CTRL_SQUARE, AKEYCODE_BUTTON_X},
	{SCE_CTRL_TRIANGLE, AKEYCODE_BUTTON_Y},
	{SCE_CTRL_L1, AKEYCODE_BUTTON_L1},
	{SCE_CTRL_R1, AKEYCODE_BUTTON_R1},
	{SCE_CTRL_START, AKEYCODE_BUTTON_START},
	{SCE_CTRL_SELECT, AKEYCODE_BUTTON_SELECT},
};

int ctrl_thread(SceSize args, void *argp)
{
	//int (*Android_Karisma_AppOnTouchEvent)(int type, int x, int y, int id) = (void *)so_symbol(&so_mod, "Android_Karisma_AppOnTouchEvent");
	//int (*Android_Karisma_AppOnJoystickEvent)(int type, float x, float y, int id) = (void *)so_symbol(&so_mod, "Android_Karisma_AppOnJoystickEvent");
	//int (*Android_Karisma_AppOnKeyEvent)(int type, int keycode) = (void *)so_symbol(&so_mod, "Android_Karisma_AppOnKeyEvent");

	int lastX[2] = {-1, -1};
	int lastY[2] = {-1, -1};

	float lx = 0.0f, ly = 0.0f, rx = 0.0f, ry = 0.0f;
	uint32_t old_buttons = 0, current_buttons = 0, pressed_buttons = 0, released_buttons = 0;

	while (1)
	{
		SceTouchData touch;
		sceTouchPeek(SCE_TOUCH_PORT_FRONT, &touch, 1);

		for (int i = 0; i < 2; i++)
		{
			if (i < touch.reportNum)
			{
				int x = (int)((float)touch.report[i].x * (float)SCREEN_W / 1920.0f);
				int y = (int)((float)touch.report[i].y * (float)SCREEN_H / 1088.0f);

				//if (lastX[i] != -1 || lastY[i] != -1)
					//Android_Karisma_AppOnTouchEvent(ACTION_DOWN, x, y, i);
				//else
					//Android_Karisma_AppOnTouchEvent(ACTION_MOVE, x, y, i);
				//lastX[i] = x;
				//lastY[i] = y;
			}
			else
			{
				//if (lastX[i] != -1 || lastY[i] != -1)
					//Android_Karisma_AppOnTouchEvent(ACTION_UP, lastX[i], lastY[i], i);
				lastX[i] = -1;
				lastY[i] = -1;
			}
		}

		SceCtrlData pad;
		sceCtrlPeekBufferPositiveExt2(0, &pad, 1);

		old_buttons = current_buttons;
		current_buttons = pad.buttons;
		pressed_buttons = current_buttons & ~old_buttons;
		released_buttons = ~current_buttons & old_buttons;

		for (int i = 0; i < sizeof(mapping) / sizeof(ButtonMapping); i++)
		{
			//if (pressed_buttons & mapping[i].sce_button)
				//Android_Karisma_AppOnKeyEvent(0, mapping[i].android_button);
			//if (released_buttons & mapping[i].sce_button)
				//Android_Karisma_AppOnKeyEvent(1, mapping[i].android_button);
		}

		lx = ((float)pad.lx - 128.0f) / 128.0f;
		ly = ((float)pad.ly - 128.0f) / 128.0f;
		rx = ((float)pad.rx - 128.0f) / 128.0f;
		ry = ((float)pad.ry - 128.0f) / 128.0f;

		if (fabsf(lx) < 0.25f)
			lx = 0.0f;
		if (fabsf(ly) < 0.25f)
			ly = 0.0f;
		if (fabsf(rx) < 0.25f)
			rx = 0.0f;
		if (fabsf(ry) < 0.25f)
			ry = 0.0f;

		// TODO: send stop event only once
		//Android_Karisma_AppOnJoystickEvent(3, lx, ly, 0);
		//Android_Karisma_AppOnJoystickEvent(3, rx, ry, 1);

		sceKernelDelayThread(1000);
	}

	return 0;
}

static int audio_port = 0;
static int disable_sound = 0;

void SetShortArrayRegion(void *env, int array, size_t start, size_t len, const uint8_t *buf)
{
	sceAudioOutOutput(audio_port, buf);
}

int sound_thread(SceSize args, void *argp)
{
	//int (*Java_com_dle_bc2_KarismaBridge_nativeUpdateSound)(void *env, int unused, int type, size_t length) = (void *)so_symbol(&so_mod, "Java_com_dle_bc2_KarismaBridge_nativeUpdateSound");

	audio_port = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_BGM, AUDIO_SAMPLES_PER_BUF / 2, AUDIO_SAMPLE_RATE, SCE_AUDIO_OUT_MODE_STEREO);

	static char fake_env[0x1000];
	memset(fake_env, 'A', sizeof(fake_env));
	*(uintptr_t *)(fake_env + 0x00) = (uintptr_t)fake_env; // just point to itself...
	*(uintptr_t *)(fake_env + 0x348) = (uintptr_t)SetShortArrayRegion;

	while (1)
	{
		if (disable_sound)
			sceKernelDelayThread(1000);
		//else
			//Java_com_dle_bc2_KarismaBridge_nativeUpdateSound(fake_env, 0, 0, AUDIO_SAMPLES_PER_BUF);
	}

	return 0;
}
*/
int main_thread(SceSize args, void *argp)
{
	int (*SDL_Main)(void) = (void *)so_symbol(&so_mod, "SDL_main");
	SDL_Main();

	// SceUID ctrl_thid = sceKernelCreateThread("ctrl_thread", (SceKernelThreadEntry)ctrl_thread, 0x10000100, 128 * 1024, 0, 0, NULL);
	// sceKernelStartThread(ctrl_thid, 0, NULL);

	// SceUID sound_thid = sceKernelCreateThread("sound_thread", (SceKernelThreadEntry)sound_thread, 0x10000100, 128 * 1024, 0, 0, NULL);
	// sceKernelStartThread(sound_thid, 0, NULL);

	// while (1) {
	//}

	return 0;
}

int main(int argc, char *argv[])
{
	sceIoRemove(LOG_PATH);

	sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE);
	sceTouchSetSamplingState(SCE_TOUCH_PORT_FRONT, SCE_TOUCH_SAMPLING_STATE_START);

	scePowerSetArmClockFrequency(444);
	scePowerSetBusClockFrequency(222);
	scePowerSetGpuClockFrequency(222);
	scePowerSetGpuXbarClockFrequency(166);

	if (check_kubridge() < 0)
		fatal_error("Error kubridge.skprx is not installed.");

	if (!file_exists("ur0:/data/libshacccg.suprx") && !file_exists("ur0:/data/external/libshacccg.suprx"))
		fatal_error("Error libshacccg.suprx is not installed.");

	if (so_load(&so_mod, SO_PATH) < 0)
		fatal_error("Error could not load %s.", SO_PATH);

	so_relocate(&so_mod);
	so_resolve(&so_mod, dynlib_functions, getNumberOfDynlibFunctions(), 1);

	patch_game();
	so_flush_caches(&so_mod);

	so_initialize(&so_mod);

	init_jni();

	SceUID thid = sceKernelCreateThread("main_thread", (SceKernelThreadEntry)main_thread, 0x40, 128 * 1024, 0, 0, NULL);
	sceKernelStartThread(thid, 0, NULL);
	return sceKernelExitDeleteThread(0);
}
